#include "FmtCvt.h"

FmtCvt::FmtCvt(uint64_t out_ch_layout, enum AVSampleFormat out_format, int out_sample_rate):
    m_out_layout(out_ch_layout),
    m_out_format(out_format),
    m_out_sample_rate(out_sample_rate),
    m_swr_ctx(NULL),
    m_out_buffer(NULL),
    m_malloc_size(8192)
{
}

FmtCvt::~FmtCvt()
{
    this->exit();
}


int FmtCvt::init(AVFrame *frame)
{
    if(NULL!=m_swr_ctx)
    {
        //printf("init agine !\n");
        return 0;
    }
    //frame->channel_layout = AV_CH_LAYOUT_MONO;

    m_swr_ctx = swr_alloc();
    swr_alloc_set_opts(m_swr_ctx, m_out_layout, m_out_format, m_out_sample_rate,
            frame->channel_layout, (AVSampleFormat)frame->format, frame->sample_rate, 0, NULL);
    int ret = swr_init(m_swr_ctx);
    if(ret<0)
    {
        fprintf(stderr, "Failed to init swr, ret = %d\n", ret);
        swr_free(&m_swr_ctx);
        m_swr_ctx = NULL;
    }
    if(NULL==m_out_buffer)
    {
        m_out_buffer = (uint8_t *) av_malloc(m_malloc_size);
    }

    printf("===================\n");
    //printf("channel_layout : %d\n", frame->channel_layout);
    printf("channel_num : %d\n", av_get_channel_layout_nb_channels(frame->channel_layout));
    printf("sample_fmt : %s\n", av_get_sample_fmt_name((AVSampleFormat)frame->format));
    printf("bytes_per_sample : %d\n", av_get_bytes_per_sample((AVSampleFormat)frame->format));
    printf("sample_rate : %d\n", frame->sample_rate);
    printf("===================\n");
    return ret;
}

int FmtCvt::exit()
{
    if(NULL!=m_swr_ctx)
    {
        swr_free(&m_swr_ctx);
        m_swr_ctx = NULL;
    }
    if(NULL!=m_out_buffer)
    {
        av_free(m_out_buffer);
        m_out_buffer = NULL;
    }
    return 0;
}

int FmtCvt::convert(AVFrame *frame, uint8_t** out_buffer_pptr)
{
    init(frame);
    if(NULL==m_swr_ctx)
    {
        printf("FmtCvt not init !\n");
        *out_buffer_pptr = NULL;
        return -1;
    }

    int dst_nb_samples = av_rescale_rnd(swr_get_delay(m_swr_ctx, m_out_sample_rate) + frame->nb_samples, m_out_sample_rate, frame->sample_rate, AV_ROUND_UP);
    int out_channals_nb = av_get_channel_layout_nb_channels(m_out_layout);
    int max_buffer_size = av_samples_get_buffer_size(NULL, out_channals_nb, dst_nb_samples, m_out_format, 1);
    if(m_malloc_size < max_buffer_size)
    {
        m_malloc_size = max_buffer_size;
        if(NULL!=m_out_buffer)
        {
            av_free(m_out_buffer);
            m_out_buffer = (uint8_t *) av_malloc(m_malloc_size);
        }
    }
    //printf("frame->nb_samples : %d\n", frame->nb_samples);
    //printf("dst_nb_samples : %d\n", dst_nb_samples);
    int out_nb_samples = swr_convert(m_swr_ctx, &m_out_buffer, dst_nb_samples, (const uint8_t **) frame->data, frame->nb_samples);
    if(out_nb_samples<0)
    {
        printf("swr_convert error = %d\n", out_nb_samples);
        *out_buffer_pptr = NULL;
        return out_nb_samples;
    }
    *out_buffer_pptr = m_out_buffer;
    //printf("out_nb_samples : %d\n", out_nb_samples);
    //int size = out_nb_samples * out_channals_nb * av_get_bytes_per_sample(dst_format);
    int size = av_samples_get_buffer_size(NULL, out_channals_nb, out_nb_samples, m_out_format, 1);
    //printf("out_size : %d\n", size);
    return size;
}

int FmtCvt::flush(uint8_t** out_buffer_pptr)
{
    //如果还有缓存在swrcontext中,第二个参数要填写0才能获取到，缓存数据
    //int fifo_size = swr_get_out_samples(m_swr_ctx, 0);
    int out_nb_samples = swr_convert(m_swr_ctx, &m_out_buffer, m_malloc_size, NULL, 0);
    if(out_nb_samples>0)
    {
        *out_buffer_pptr = m_out_buffer;
        int out_channals_nb = av_get_channel_layout_nb_channels(m_out_layout);
        int size = av_samples_get_buffer_size(NULL, out_channals_nb, out_nb_samples, m_out_format, 1);
        return size;
    }else{
        return 0;
    }
}

